﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using MyCompany.MyProject.Common;
using MyCompany.MyProject.Common.DB;
using MyCompany.MyProject.Common.GlobalVaribale;
using MyCompany.MyProject.Common.HttpContextUser;
using MyCompany.MyProject.Extensions.Auth;
using MyCompany.MyProject.Model.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace MyCompany.MyProject.Extensions.ServiceExtensions;

public static class AuthorizationSetup
{
    public static void AddAuthorizationSetup(this IServiceCollection services)
    {
        if (services == null) throw new ArgumentNullException(nameof(services));

        // 以下四种常见的授权方式。
        // 1 只需要在API的控制器上添加特性 [Authorize(Role="Admin,System")]

        // 2 这个和上面的基本相同，好处就是不用在控制器上写多个 roles，然后这样写 [Authorize(Policy="Adimin")]
        services.AddAuthorization(options =>
        {
            options.AddPolicy("Client", policy => policy.RequireRole("Client").Build());
            options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build());
            options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System"));
            options.AddPolicy("A_S_O", policy => policy.RequireRole("Admin", "System", "Others"));
        });

        // 3 自定义复杂的授权策略
        var symmetricKeyAsBase64 = AppSecretConfig.Audience_Secret_String;
        var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
        var signingKey = new SymmetricSecurityKey(keyByteArray);
        var Issuer = AppSettings.app("TokenParms", "Issuer");
        var Audience = AppSettings.app("TokenParms", "Audience");
        var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
        var expires = AppSettings.app("TokenParms", "Expires");
        var refreshTime = AppSettings.app("TokenParms", "RefreshTime");

        // 如果要数据库动态绑定，这里先留个空，后面处理器里动态赋值
        var permission = new List<PermissionItem>();

        // 角色与接口的权限要求参数
        var permissionRequirement = new PermissionRequirement(
            "/api/denied", // 拒绝授权跳转地址
            permission,
            ClaimTypes.Role, // 基于角色的授权
            Issuer, // 发行人
            Audience, // 订阅人
            signingCredentials, // 签名凭据
            expiration: TimeSpan.FromSeconds(Convert.ToDouble(expires)), // 接口的过期时间
            refreshTime:TimeSpan.FromMinutes(Convert.ToDouble(refreshTime))
            );
        services.AddAuthorization(options =>
        {
            options.AddPolicy(Common.GlobalVaribale.Permission.Name, policy => policy.Requirements.Add(permissionRequirement));
        });

        // 4 基于 Scope 策略授权
        //services.AddAuthorization(options =>
        //{
        //    options.AddPolicy("Scope_Wja_Policy", builder =>
        //    {
        //        // 客户端 Scope 中包含 wja_api_xx 才能访问
        //        // 需要引用 IdentityServer4.AccessTokenValidation nuget包
        //        builder.RequireScope("wja_api_xx");
        //    });
        //});

        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddScoped<IUser ,AspNetUser>();
        services.AddScoped<IAuthorizationHandler,PermissionRequirementHandler>();
        services.AddSingleton(permissionRequirement);
    }
}
